home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Megarom
/
Megarom Macintosh CD Software (Quantum Leap)(1992).iso
/
COMMUNICATION
/
BBS Software Systems
/
BBS-0.60
/
simple
< prev
next >
Wrap
Text File
|
1990-05-30
|
29KB
|
1,619 lines
/*
* Copyright © 1990 Paul Campbell, Taniwha Systems Design
* All Rights Reserved.
* Right to redistribute this software with the Taniwha BBS
* is hereby granted.
*/
const NULL = 0, /* nil pointer */
USERNLEN = 30, /* length of a user name */
TIMEOUT = 7200, /* timeout - 2 minutes - set to -1 to disable */
MAPSIZE = 128; /* limit to the # lines in an edited file */
global UserRecord[40], /* user record from user file */
User[USERNLEN], /* user name */
Directory[256], /* directory name of root directory for BBS system */
Tmp[128], /* temporary array */
Tmp1[128], /* temporary array */
Tmp2[128], /* temporary array */
TmpName[64], /* temporary file name */
XUser[USERNLEN], /* other user name (used for destination of mail etc) */
MailHdr[128], /* mail file header record */
Subject[128], /* mail subject */
nextc, /* next input char from edit_command() */
col, /* editor screen column */
line, /* editor screen line */
lineoffset, /* index into screen of the start of the current line */
lcount, /* editor line count */
pos, /* editor line position */
efree, /* editor next free block */
elist, /* first in free edit block list */
lmod[23], /* line has been modified */
screen[1840], /* current screen being edited */
ftmp, /* temp file we have open */
fedit, /* temp file we have open for editing */
fuser, /* user file we have open */
MailState[6], /* mail control file */
sysop, /* true if we are 'sysop' */
timeout, /* system wide timeout */
Map[MAPSIZE]; /* edit file map */
/*
* system-wide global variable use:
*
* A - unique number, incremented on each use
*
* system-wide lock uses
*
* 0 - user file
* 1 - lock on mail system
*/
"simple"
{
if (gettype() == 0) {
timeout = -1;
} else {
timeout = TIMEOUT; /* set to -1 for no timeout */
}
for (;;) {
setuser("");
sysop = 0;
getdirectory(Directory);
setstate("Idle");
if (!enabled())
quit();
connect();
setstate("Login");
if (!login()) {
disconnect();
continue;
}
setstate("Active");
message_of_the_day();
setuser(User);
commands();
disconnect();
resched(); /* These recheds required for the CommToolbox to get the port back */
resched(); /* into a sane state before trying to connect again - no one knows why :-)*/
resched();
}
}
do_hangup()
{
setuser("");
if (TmpName[0]) {
remove(TmpName);
TmpName[0] = 0;
}
restart();
}
commands()
{
local c, j;
for (;;) {
stty('e', 0);
stty('l', 0);
if (sysop) {
j = "C(onfig) ";
} else {
j = "";
}
printf("Main: %sP(assword) R(ead mail) S(end mail) F(iles) L(ogout) > ", j);
c = getchartime(timeout);
stty('e', 1);
stty('l', 1);
if (c == -2) {
return;
}
putchar(c);
putchar('\n');
switch(c) {
case 'P':
case 'p':
set_password(User, 0);
break;
case 'C':
case 'c':
if (sysop)
config();
break;
case 'F':
case 'f':
do_files();
break;
case 'R':
case 'r':
rmail();
break;
case 'S':
case 's':
smail(0, 0, 0);
break;
case 'L':
case 'l':
return;
}
}
}
/*
* rmail searches for mail to the user
* by looking in the subdirectory 'mail:USER'
*/
rmail()
{
local i, first, last, this, mod, c, done, x;
i = get_mailstate(User, 0);
if (i < 0) {
printf("Mail Problem\n");
return;
}
first = (MailState[0]<<8)|MailState[1];
last = (MailState[2]<<8)|MailState[3];
this = (MailState[4]<<8)|MailState[5];
if (i == 0 || first > last) {
printf("No Mail\n");
return;
}
mod = 0;
printf("First message %d, Last Message %d, Current Message %d\n",
first, last, this);
for (done = 0;!done;) {
stty('e', 0);
stty('l', 0);
printf("Mail(%d): A(ll) D(el) R(eply) H(eader) L(ist) T(his) Q(uit) +/-> ", this);
c = getchartime(timeout);
stty('e', 1);
stty('l', 1);
if (c == -2)
break;
putchar(c);
putchar('\n');
x = 0;
switch(c) {
case '-':
x = 1;
if (this > first) {
mod = 1;
this--;
}
case '\n':
case '\r':
case '+':
if (x == 0 && this < last) {
mod = 1;
this++;
}
case 'T':
case 't':
display_mail(this);
break;
case 'r':
case 'R':
reply_mail(this);
break;
case 'D':
case 'd':
mod = 1;
first = delete_mail(first, this, last);
break;
case 'L':
case 'l':
pr_subjects(this, last);
break;
case 'A':
case 'a':
pr_subjects(first, last);
break;
case 'Q':
case 'q':
done = 1;
break;
}
}
if (mod && get_mailstate(User, 1) == 1) {
MailState[0] = first>>8;
MailState[1] = first;
MailState[4] = this>>8;
MailState[5] = this;
set_mailstate(User, 1);
}
}
/*
* control file contains:
*
* bytes 0-1 first mail message
* 2-3 last mail message
* 4-6 last message read
*/
get_mailstate(user, x)
{
local i, j;
lock(1);
sprintf(Tmp2, "%smail:%s:control", Directory, user);
ftmp = fopen(Tmp2, "r+");
if (ftmp) {
i = fread(MailState, 6, 1, ftmp);
if (i != 1 || !x) {
fclose(ftmp);
}
if (i != 1)
i = -1;
} else {
i = 0;
}
if (i != 1 || !x)
unlock(1);
return(i);
}
set_mailstate(user, x)
{
if (!x) {
lock(1);
sprintf(Tmp2, "%smail:%s:control", Directory, user);
ftmp = fopen(Tmp2, "r+");
}
if (ftmp) {
fseek(ftmp, 0, 0);
fwrite(MailState, 6, 1, ftmp);
fclose(ftmp);
}
if (x != 2)
unlock(1);
}
delete_mail(first, this, last)
{
sprintf(Tmp2, "%smail:%s:%d", Directory, User, this);
remove(Tmp2);
if (this == first) {
for (;;) {
first++;
if (first > last)
break;
sprintf(Tmp2, "%smail:%s:%d", Directory, User, first);
ftmp = fopen(Tmp2, "r");
if (ftmp) {
fclose(ftmp);
break;
}
}
}
return(first);
}
reply_mail(this)
{
local i, m, c;
sprintf(Tmp2, "%smail:%s:%d", Directory, User, this);
ftmp = fopen(Tmp2, "r");
if (ftmp == NULL) {
printf("No message %d to reply to\n", this);
return;
}
for (;;) {
c = fgetc(ftmp);
if (c == '\'' || c == '\r' || c <= 0)
break;
}
if (c == '\'') {
for (i = 0;;i++) {
c = fgetc(ftmp);
if (c == '\'' || c == '\r' || c <= 0)
break;
XUser[i] = c;
}
XUser[i] = 0;
if (i == 0)
c = -1;
}
if (c == '\'') {
for (;;) {
c = fgetc(ftmp);
if (c == '\'' || c == '\r' || c <= 0)
break;
}
}
if (c == '\'') {
for (i = 0;;i++) {
c = fgetc(ftmp);
if (c == '\'' || c == '\r' || c <= 0)
break;
Subject[i] = c;
}
Subject[i] = 0;
if (i == 0)
c = -1;
}
if (c == '\'') {
for (;;) {
c = fgetc(ftmp);
if (c == '\r' || c <= 0)
break;
}
m = edit_load(ftmp);
fclose(ftmp);
if (Subject[0] != 'R' ||
Subject[1] != 'e' ||
Subject[2] != ':') {
strcpy(Tmp1, "Re: ");
} else {
Tmp1[0] = 0;
}
strcat(Tmp1, Subject);
strcpy(Tmp2, XUser);
smail(Tmp2, Tmp1, m);
} else {
printf("Malformed file header\n");
fclose(ftmp);
}
}
pr_subjects(s, e)
{
local i, x, j, c;
for (i = s, x = 0; i <= e; i++){
sprintf(Tmp2, "%smail:%s:%d", Directory, User, i);
ftmp = fopen(Tmp2, "r");
if (ftmp) {
for (j = 0;j < 126; j++) {
Tmp[j] = c = fgetc(ftmp);
if (c == '\r' || c < 0)
break;
}
Tmp[j] = 0;
fclose(ftmp);
if (Tmp[0]) {
x = 1;
if (cantput())
return;
printf("%d: %s\n", i, Tmp);
}
}
}
if (x == 0)
printf("No mail found\n");
}
display_mail(this)
{
sprintf(Tmp2, "%smail:%s:%d", Directory, User, this);
ftmp = fopen(Tmp2, "r");
if (ftmp == NULL) {
printf("No mail %d (deleted)\n", this);
return;
}
file_cat(ftmp);
fclose(ftmp);
}
/*
* send mail
*/
smail(to, subject, xf)
{
local m, i, x, c, s, done;
if (to == 0) {
printf("To> ");
if (readlinetime(XUser, 40, timeout) != 0)
return;
} else {
strcpy(XUser, to);
}
if (XUser[0] == 0)
return;
if (subject == 0) {
printf("Subject> ");
if (readlinetime(Subject, 80, timeout) != 0)
return;
} else {
strcpy(Subject, subject);
}
if (xf) {
m = xf;
} else {
m = edit_empty(1);
if (m == NULL) {
printf("Cannot open temporary file for editing\n");
return;
}
}
done = 0;
for (c = 'e';;) {
switch(c) {
case 'h':
case 'H':
printf("To> ");
if (readlinetime(XUser, 40, timeout) != 0) {
done = 1;
break;
}
printf("Subject> ");
if (readlinetime(Subject, 80, timeout) != 0) {
done = 1;
break;
}
break;
case 'e':
case 'E':
edit(m);
break;
case 's':
case 'S':
i = 0;
x = 0;
s = 0;
done = 1;
for (;c!= 0;i++) {
c = XUser[i];
if (s == 0) {
if (c == 0)
break;
if (c != ' ' && c != ',') {
Tmp1[x++] = c;
s = 1;
}
} else {
if (c == 0 || c == ',') {
while (x > 0 && Tmp1[x-1] == ' ')
x--;
if (x != 0) {
Tmp1[x] = 0;
if (send_mail(Tmp1, Subject, m)) {
printf("Can't send mail to %s\n", Tmp1);
done = 0;
} else {
printf("Sent to %s\n", Tmp1);
}
x = 0;
}
s = 0;
} else {
Tmp1[x++] = c;
}
}
}
break;
case 'a':
case 'A':
done = 1;
break;
}
if (done)
break;
stty('e', 0);
stty('l', 0);
printf("Send Mail: A(bort) E(dit mail) H(eader) S(end mail) > ");
c = getchartime(timeout);
stty('e', 1);
stty('l', 1);
if (c == -2)
break;
putchar(c);
putchar('\n');
}
fclose(m);
if (m == fedit) {
if (TmpName[0]) {
remove(TmpName);
TmpName[0] = 0;
}
}
}
send_mail(to, subject, f)
{
local last, i;
i = get_mailstate(to, 1);
if (i != 1) {
lock(1);
ftmp = fopen(Tmp2, "w+");
if (ftmp == NULL) {
unlock(1);
return(1);
}
last = -1;
MailState[4] = 0;
MailState[5] = 1;
} else {
last = (MailState[2]<<8)|MailState[3];
}
if (last == -1) { /* no mail at all */
MailState[1] = 1;
MailState[3] = 0;
last = 1;
} else {
last++;
MailState[2] = last>>8;
MailState[3] = last;
}
set_mailstate(to, 2);
sprintf(Tmp2, "%smail:%s:%d", Directory, to, last);
ftmp = fopen(Tmp2, "w+");
if (ftmp == NULL) {
unlock(1);
return(1);
}
fprintf(ftmp, "From: '%s' Subject: '%s'\r", User, subject);
edit_save(f, ftmp);
fclose(ftmp);
unlock(1);
return(0);
}
/*
* This routine logs a user on, the user file record will be
* in global array 'E'
*
*/
login()
{
local c, done, try, passwd;
done = 0;
for (try = 0;try < 3;try++) {
switch(try) {
case 0:
stty('s', 2400);
break;
case 1:
stty('s', 1200);
break;
case 2:
stty('s', 300);
break;
}
for (;;) {
printf("\nLogin to BBS:");
if (readlinetime(User, 40, timeout) != 0)
break;
if (User[0] == 0)
continue;
passwd = get_password("Password:", 1);
if (passwd == 0)
break;
if (userinfo(User, passwd, 0, 0, 0)) {
sysop = strcmp("sysop", User) == 0;
return(1);
}
}
}
return(0);
}
/*
* edit - edits a file (be it empty or otherwise
*
* a VERY simple text editor,
*
* Commands:
* <char> insert a printable char
* DEL delete the letter to the left of the cursor (if there is one)
* or join 2 lines
* CR insert a new line (split an existing one)
* ESC [ A cursor up
* ESC O A
* ESC A
* ESC [ B cursor down
* ESC O B
* ESC B
* ESC [ C cursor left
* ESC O C
* ESC C
* ESC [ D cursor right
* ESC O D
* ESC D
* ^L refresh
* ^D Quit
*/
edit(f)
{
local cmd, i, len, b, x, k, j, xcol, tab, wait;
pos = 0;
col = 0;
line = 0;
xcol = 0;
tab = 0;
wait = 0;
stty('e', 0);
stty('l', 0);
x = 0;
for (i = 0; i < 23; i++) {
if (i < lcount) {
fseek(f, Map[i]*80, 0);
fread(&screen[x], 80, 1, f);
} else {
screen[x] = 0;
}
lmod[i] = 0;
x += 80;
}
lineoffset = 0;
len = strlen(&screen[0]);
refresh(f);
for (;;) {
if (tab > 0) {
i = 0;
nextc = ' ';
tab--;
} else {
i = edit_command();
if (wait) {
refresh();
wait = 0;
continue;
}
}
switch(i) {
case 0: /* insert nextc */
if (len >= 79) {
putchar(7);
break;
}
xcol = 0;
lmod[line] = lmod[line]|1;
if (col == len) {
screen[lineoffset+col] = nextc;
col++;
len++;
screen[lineoffset+col] = 0;
putchar(nextc);
break;
}
for (i = (lineoffset+len);i > (lineoffset+col);i--)
screen[i] = screen[i-1];
screen[lineoffset+col] = nextc;
len++;
screen[lineoffset+len] = 0;
putstr(&screen[lineoffset+col]);
col++;
goto(col, line);
break;
case 1: /* up cursor */
if (line > 0) {
line--;
lineoffset -= 80;
len = strlen(&screen[lineoffset]);
} else {
if (pos == 0)
break;
edit_purge(f, 22, 22);
for (i = 22, j=(22*80);i > 0; i--, j -= 80) {
lmod[i] = lmod[i-1];
strcpy(&screen[j], &screen[j-80]);
}
scroll_down(0, 22);
goto(0,0);
fseek(f, Map[pos-1]*80, 0);
fread(&screen[0], 80, 1, f);
putstr(&screen[0]);
lmod[0] = 0;
}
pos--;
if (xcol && col < xcol)
col = xcol;
if (col > len) {
xcol = col;
col = len;
}
goto(col, line);
break;
case 2:
if (pos == (lcount-1))
break;
if (line < 22) {
line++;
lineoffset += 80;
len = strlen(&screen[lineoffset]);
} else {
edit_purge(f, 0, 0);
for (i = 0, j=0;i < 22; i++, j += 80) {
lmod[i] = lmod[i+1];
strcpy(&screen[j], &screen[j+80]);
}
scroll_up(0, 22);
goto(0,22);
fseek(f, Map[pos+1]*80, 0);
x=fread(&screen[lineoffset], 80, 1, f);
putstr(&screen[lineoffset]);
lmod[22] = 0;
}
pos++;
if (xcol && col < xcol)
col = xcol;
if (col > len) {
xcol = col;
col = len;
}
goto(col, line);
break;
case 3:
if (col < len) {
col++;
xcol = 0;
}
goto(col, line);
break;
case 4:
if (col > 0) {
col--;
xcol = 0;
}
goto(col, line);
break;
case 5:
refresh(f);
break;
case 6:
clear();
edit_purge(f, 0, 22);
stty('e', 1);
stty('l', 1);
return;
case 7:
if (col == 0) {
if (pos == 0)
break;
if (line == 0) {
fseek(f, Map[pos-1]*80, 0);
fread(Tmp, 80, 1, f);
i = strlen(Tmp);
if ((i + len) > 79) { /* too long */
putchar('\007');
break;
}
strcpy(&Tmp[i], &screen[0]);
strcpy(&screen[0], Tmp);
len += i;
edit_freeblock(Map[pos]);
col = i;
lcount--;
for (i = pos; i < lcount; i++)
Map[i] = Map[i+1];
pos--;
goto(0, 0);
putstr(&screen[0]);
} else {
i = strlen(&screen[lineoffset-80]);
if ((i+len) > 79) {
putchar('\007');
break;
}
col = i;
goto(col, line-1);
putstr(&screen[lineoffset]);
strcpy(&screen[lineoffset-80+i], &screen[lineoffset]);
for (i = line, j = pos, k = lineoffset; i < 22; i++, j++, k += 80) {
if (j > lcount)
break;
strcpy(&screen[k], &screen[k+80]);
}
len += col;
edit_freeblock(Map[pos]);
lcount--;
for (i = pos; i < lcount; i++)
Map[i] = Map[i+1];
for (i = line; i < 22; i++)
lmod[i] = lmod[i+1];
pos--;
scroll_up(line, 22);
i = pos-line+22;
if (i >= lcount) {
goto(0, 22);
putchar('~');
screen[80*22] = 0;
} else {
fseek(f, Map[i]*80, 0);
fread(&screen[80*22], 80, 1, f);
goto(0, 22);
putstr(&screen[80*22]);
lmod[22] = 0;
}
line--;
lineoffset -= 80;
}
goto(col, line);
lmod[line] = lmod[line]|1;
break;
}
xcol = 0;
col--;
len--;
lmod[line] = lmod[line]|1;
if (col == len) {
screen[lineoffset+len] = 0;
goto(col, line);
putchar(' ');
goto(col, line);
break;
}
goto(col, line);
putstr(&screen[lineoffset+col+1]);
putchar(' ');
goto(col, line);
for (i = (lineoffset+col); i < (lineoffset+len); i++)
screen[i] = screen[i+1];
screen[lineoffset+len] = 0;
break;
case 8:
b = edit_newblock(f, 0);
xcol = 0;
if (col != len)
erase_eol();
if (line == 22) {
edit_purge(f, 0, 0);
x = screen[lineoffset+col];
screen[lineoffset+col] = 0;
for (i = 0, j = 0;i < 22; i++, j += 80) {
lmod[i] = lmod[i+1];
strcpy(&screen[j], &screen[j+80]);
}
screen[lineoffset+col] = x;
strcpy(&screen[lineoffset], &screen[lineoffset+col]);
if (len != col)
lmod[21] = lmod[21]|1;
} else {
edit_purge(f, 22, 22);
for (i = 22, j=(22*80);i > (line+1); i--, j -= 80) {
lmod[i] = lmod[i-1];
strcpy(&screen[j], &screen[j-80]);
}
strcpy(&screen[lineoffset+80], &screen[lineoffset+col]);
screen[lineoffset+col] = 0;
if (len != col)
lmod[line] = lmod[line]|1;
}
len -= col;
col = 0;
pos++;
for (i = lcount; i > pos; i--)
Map[i] = Map[i-1];
lcount++;
Map[pos] = b;
if (line == 22) { /* scroll everything up */
scroll_up(0, 22);
} else {
line++;
lineoffset += 80;
scroll_down(line, 22);
}
lmod[line] = lmod[line]|1;
goto(0, line);
if (col != len) {
putstr(&screen[lineoffset]);
goto(0, line);
}
break;
case 9:
i = col&7;
if (i == 0) {
tab = 8;
} else {
tab = 8 - i;
}
break;
case 10:
clear(); putstr("Taniwha BBS Editor");
goto(0, 1); putstr("==================");
goto(0, 3); putstr("Type any character to insert it at the cursor");
goto(0, 5); putstr("Type type the 'Delete' or 'Backspace' key to delete the character");
goto(0, 6); putstr(" to the left off the cursor, or, if the cursor is at the left");
goto(0, 7); putstr(" of the screen to join the current line to the previous one.");
goto(0, 9); putstr("Type 'return' to insert a new line at the cursor");
goto(0, 11); putstr("Use the arrow keys to move on the screen (or 'ESC' A/B/C/D to");
goto(0, 12); putstr(" move up/down/left right)");
goto(0, 14); putstr("Type Ctrl-D (hold down the 'Control' key and type D)");
goto(0, 15); putstr(" to exit the editor)");
goto(0, 22); putstr("Type any character to continue");
wait = 1;
break;
}
}
}
/*
* write back the changed lines to the backing store
*/
edit_purge(f, s, e)
{
local i, x;
for (i = s; i <= e; i++)
if (lmod[i]) {
x = pos-line+i;
if (x >= lcount)
break;
fseek(f, Map[x]*80, 0);
fwrite(&screen[i*80], 80, 1, f);
}
}
/*
* append the edit file f to f2
*/
edit_save(f, f2)
{
local i, j;
for (i = 0; i < lcount; i++) {
fseek(f, Map[i]*80, 0);
fread(Tmp, 80, 1, f);
j = strlen(Tmp);
Tmp[j] = '\r';
fwrite(Tmp, j+1, 1, f2);
}
}
/*
* make a new edit file containing the contents of the rest of file f
*/
edit_load(f)
{
local m;
m = edit_empty(0);
if (m == NULL) {
return(NULL);
}
edit_append(m, f);
return(m);
}
/*
* load the rest of file f into edit file m
*/
edit_append(m, f)
{
local l, x, i, c;
l = 0;
x = 0;
i = 0;
for (;;) {
if (l == i) {
l = fread(Tmp2, 1, 128, f);
if (l <= 0)
break;
i = 0;
}
c = Tmp2[i];
i++;
if (c == '\r') {
Tmp1[x] = 0;
x = 0;
Map[lcount] = edit_newblock(m, 1);
fseek(m, 80*Map[lcount], 0);
fwrite(Tmp1, 80, 1, m);
lcount++;
if (lcount == MAPSIZE)
break;
} else {
if (x < 79) {
Tmp1[x] = c;
x++;
}
}
}
if (x > 0 || lcount == 0) {
Tmp1[x] = 0;
Map[lcount] = edit_newblock(m, 1);
fseek(m, 80*Map[lcount], 0);
fwrite(Tmp1, 80, 1, m);
lcount++;
}
}
/*
* make a temporary edit file
*/
edit_empty(add)
{
local i;
A++;
i = A; /* use global variable to get unique file name */
sprintf(TmpName, "%stmp:%d", Directory, i);
fedit = fopen(TmpName, "w+");
if (fedit == NULL)
return(NULL);
elist = 0;
efree = 0;
if (add) {
Map[0] = edit_newblock(fedit, 1);
Tmp[0] = 0;
fseek(fedit, Map[0]*80, 0);
fwrite(Tmp, 80, 1, fedit); /* add an empty line */
lcount = 1;
} else {
lcount = 0;
}
return(fedit);
}
/*
* what follows are for a vt100, change to suit your own terminal(s)
*/
/*
* scroll up 1 line the screen between lines t(op) and b(ottom)
*/
scroll_up(t, b)
{
set_scroll(t, b);
goto(0, b);
putchar('\n');
clear_scroll();
}
/*
* scroll down 1 line the screen between lines t(op) and b(ottom)
*/
scroll_down(t, b)
{
set_scroll(t, b);
goto(0, t);
putstr("\033M");
clear_scroll();
}
/*
* put the screen into scroll mode between lines t and b
*/
set_scroll(t, b)
{
printf("\033[%d;%dr", t+1,b+1);
}
/*
* clear scrolling region
*/
clear_scroll()
{
putstr("\033[r");
}
/*
* erase the line from the cursor to the end
*/
erase_eol()
{
putstr("\033[K");
}
/*
* clear the whole screen
*/
clear()
{
putstr("\033[H\033[J");
}
/*
* go to a particular screen location
*/
goto(x, y)
{
printf("\033[%d;%dH",y+1,x+1);
}
/*
* redraw the screen
*/
refresh(f)
{
local i, j;
clear_scroll();
clear();
for (i = 0, j = 0; i < 23; i++, j += 80) {
goto(0, i);
if ((pos-line+i) < lcount) {
putstr(&screen[j]);
} else {
putchar('~');
}
}
goto(0, 23);
putstr("^D - quit, DEL delete, ^L refresh - use arrows to move, <ESC> ? for help");
goto(col, line);
}
cantput()
{
local x, y;
y = 1;
resched();
resched();
x = peekc();
for (;;) {
if (y && x < 0)
return(0);
x = getchar();
if (x == 's' || x == 'S' || x == 0x13) {
x = getchar();
y = 0;
continue;
}
if (x == 'q' || x == 'Q' || x == 0x11)
return(0);
if (x == 3 || x == 'k' || x == 'K')
return(1);
}
}
/*
* allocate an 80 byte block from the file
*/
edit_newblock(f, a)
{
local x;
if (elist) {
x = elist;
fseek(f, elist*80, 0);
fread(Tmp, 80, 1, f);
elist = Tmp[0];
return(x);
}
x = efree;
if (a == 0) {
fseek(f, efree*80, 0);
fwrite(Tmp, 80, 1, f);
}
efree++;
return(x);
}
/*
* free a block from the file
*/
edit_freeblock(f, x)
{
local x;
if (x == (efree-1)) {
efree = x;
return;
}
Tmp[0] = elist;
fseek(f, x*80, 0);
fwrite(Tmp, 80, 1, f);
elist = x;
}
/*
* edit commands, returned in d:
*
* 0 - insert char
* 1 - up
* 2 - down
* 3 - left
* 4 - right
* 5 - refresh
* 6 - quit
* 7 - delete
* 8 - new line
* 9 - tab
* 10 - help
*/
edit_command()
{
local d;
d = 0;
for (;;) {
nextc = getchartime(timeout);
if (nextc == -2)
return(6);
switch(d) {
case 0:
if (nextc >= ' ' && nextc < 0x7f)
return(0);
if (nextc == '\033') {
d = 1;
continue;
}
if (nextc == 9) {
return(9);
}
if (nextc == 0x7f || nextc == 8) {
return(7);
}
if (nextc == 13 || nextc == 11)
return(8);
if (nextc == 4)
return(6);
if (nextc == 12)
return(5);
break;
case 1:
if (nextc == '?')
return(10);
if (nextc == 'O' || nextc == '[') {
d = 2;
continue;
}
case 2:
if (nextc >= 'A' && nextc <= 'D')
return(nextc - 'A' + 1);
if (nextc >= 'a' && nextc <= 'd')
return(nextc - 'a' + 1);
d = 0;
break;
}
}
}
/*
* This routine takes the user name in global array A
* and a 16-bit hashed password in global variable a
* it locks updates between multiple users.
*
* If add is set then an entry is also added
*
* If del is set and a==0 or a==the password in the entry
* the entry is deleted
*
* If pass is set then set the password
*
*/
userinfo(name, passwd, add, del, pass)
{
local r, i, c;
passwd &= 0xffff;
r = 0;
i = -1;
sprintf(Tmp, "%scontrol:User File", Directory);
lock(0); /* lock the user data base */
fuser = fopen(Tmp, "r+");
if (fuser == NULL) {
fuser = fopen(Tmp, "w");
if (fuser == NULL) {
sprintf(Tmp, "%scontrol", Directory);
mkdir(Tmp);
sprintf(Tmp, "%scontrol:User File", Directory);
fuser = fopen(Tmp, "w");
if (fuser == NULL) {
unlock(0);
return(0);
}
}
strcpy(Tmp, "sysop");
Tmp[38] = 0;
Tmp[39] = 1;
fwrite(Tmp, 40, 1, fuser);
strcpy(Tmp, "guest");
Tmp[38] = 0;
Tmp[39] = 1;
fwrite(Tmp, 40, 1, fuser);
fclose(fuser);
sprintf(Tmp, "%smail", Directory);
mkdir(Tmp);
sprintf(Tmp, "%smail:sysop", Directory);
mkdir(Tmp);
sprintf(Tmp, "%smail:guest", Directory);
mkdir(Tmp);
sprintf(Tmp, "%scontrol:User File", Directory);
fuser = fopen(Tmp, "r+");
}
if (fuser) {
for (;;) {
i = fread(Tmp, 40, 1, fuser);
if (i <= 0) {
if (add) {
name[38] = passwd>>8;
name[39] = passwd;
if (r != 0) {
fseek(fuser, r-40, 0);
} else {
fseek(fuser, 0, 2);
}
fwrite(name, 40, 1, fuser);
memcpy(UserRecord, name, 40);
r = 1;
} else {
r = 0;
}
fclose(fuser);
unlock(0);
return(r);
}
if (Tmp[0] == 0) {
if (r == 0)
r = ftell(fuser);
} else
if (strcmp(Tmp, name) == 0) {
c = (Tmp[38]<<8)|Tmp[39];
if (pass || (del && (passwd == 0 || passwd == c || sysop))) {
if (del) {
Tmp[0] = 0;
} else
if (pass) {
Tmp[38] = passwd>>8;
Tmp[39] = passwd;
}
fseek(fuser, -40, 1);
fwrite(Tmp, 40, 1, fuser);
}
memcpy(UserRecord, Tmp, 40);
fclose(fuser);
unlock(0);
return(pass || passwd == c || passwd == 0 || sysop);
}
}
}
unlock(0);
return(0);
}
/*
* print the contents of a file
*/
file_cat(f)
{
local i, l;
for (;;) {
if (cantput())
break;
l = fread(Tmp, 1, 128, f);
if (l <= 0)
break;
for (i = 0; i < l; i++)
if (Tmp[i] == '\r')
Tmp[i] = '\n';
putline(Tmp, l);
}
}
/*
* print 'message of the day'
*/
message_of_the_day()
{
sprintf(Tmp2, "%smessage", Directory);
ftmp = fopen(Tmp2, "r");
if (ftmp) {
file_cat(ftmp);
fclose(ftmp);
}
}
config()
{
local c;
for (;;) {
stty('e', 0);
stty('l', 0);
printf("Config: A(dd user) D(elete user) P(assword) Q(uit) > ");
c = getchar();
stty('e', 1);
stty('l', 1);
putchar(c);
putchar('\n');
switch(c) {
case 'A':
case 'a':
printf("Add User: ");
readline(XUser, 40);
set_password(XUser, 1);
sprintf(Tmp, "%smail:%s", Directory, XUser);
mkdir(Tmp);
break;
case 'D':
case 'd':
printf("Delete User: ");
readline(XUser, 40);
if (!userinfo(XUser, 0, 0, 1, 0))
printf("Invalid user '%s'\n", XUser);
break;
case 'P':
case 'p':
printf("Password User: ");
readline(XUser, 40);
set_password(XUser, 0);
break;
case 'Q':
case 'q':
return;
}
}
}
set_password(user, add)
{
local i1, i2;
i1 = get_password("New Password: ", 0);
i2 = get_password("Re-enter new Password: ", 0);
if (i1 != i2) {
printf("Passwords not the same, try again\n");
return;
}
if (!userinfo(user, i1, add, 0, 1))
printf("Invalid user '%s'\n", user);
}
get_password(prompt, t)
{
local passwd, done, c;
done = 0;
stty('e', 0);
stty('l', 0);
putstr(prompt);
passwd = 0;
for (;;) {
c = getchartime(timeout);
if (c == -2)
break;
if (t && (c&0x80 || c == 0))
break;
if (c == '\n' || c == '\r') {
done = 1;
break;
}
passwd = passwd + (c<<1);
putchar('.');
}
stty('e', 1);
stty('l', 1);
putchar('\n');
if (t && !done)
return(0);
if (passwd == 0)
passwd = 1;
return(passwd);
}
/*
* file upload/download area
*/
do_files()
{
local c, t, f;
f = "XMODEM";
t = "Method StraightXMODEM Option Standard Creator \"ttxt\" Timeout 5 Retry 5 RemoteName False";
for (;;) {
stty('e', 0);
stty('l', 0);
printf("Files: D(ownload) U(pload) L(ist) Q(uit) > ");
c = getchartime(timeout);
stty('e', 1);
stty('l', 1);
if (c == -2)
return;
putchar(c);
putchar('\n');
switch(c) {
case 'D':
case 'd':
printf("File> ");
if (readlinetime(Tmp, 40, timeout) != 0)
continue;
if (Tmp[0] == 0)
continue;
sprintf(Tmp2, "%sfiles:%s", Directory, Tmp);
ftmp = fopen(Tmp2, "r");
if (ftmp == NULL) {
printf("File %s doesn't exist\n", Tmp);
break;
}
fclose(ftmp);
if (ft_new(f, t)) {
printf("Transfer Failed\n");
break;
}
sprintf(Tmp2, "%sfiles", Directory);
if (ft_start(Tmp2, Tmp, 1))
printf("Transfer Failed\n");
ft_dispose();
break;
case 'U':
case 'u':
printf("File> ");
if (readlinetime(Tmp, 40, timeout) != 0)
continue;
if (Tmp[0] == 0)
continue;
sprintf(Tmp2, "%sfiles:%s", Directory, Tmp);
ftmp = fopen(Tmp2, "r");
if (ftmp) {
fclose(ftmp);
printf("File %s already exists\n", Tmp);
break;
}
if (ft_new(f, t)) {
printf("Transfer Failed\n");
break;
}
sprintf(Tmp2, "%sfiles", Directory);
if (ft_start(Tmp2, Tmp, 0))
printf("Transfer Failed\n");
ft_dispose();
break;
case 'L':
case 'l':
break;
case 'Q':
case 'q':
return;
}
}
}